package com.sitech.portal.panels.service.impl;

import com.sitech.portal.panels.ValueType;
import com.sitech.portal.panels.dao.TbCfgPanelSettingDao;
import com.sitech.portal.panels.domain.TbCfgPanelSetting;
import com.sitech.portal.panels.service.PanelSettingService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by liujhc on 1/3.
 */
public class PanelSettingServiceImpl implements PanelSettingService {

    @Autowired
    private TbCfgPanelSettingDao dao;
    private static final String SUB_SEPARATOR = ".";

    @Override
    public Map<String, Object> queryPanelSettingsAsMap(String panelId) {
        return reverseTransform(panelId, new HashMap<String, Object>());
    }

    @Override
    public List<Object> queryPanelSettingsAsList(String panelId) {
        return reverseTransform(panelId, new ArrayList<Object>());
    }

    @Override
    public void savePanelSettings(String panelId, Object settings) {
        List<TbCfgPanelSetting> list = transToTable(panelId, settings, new ArrayList<TbCfgPanelSetting>());
        dao.savePanelSettings(list);
    }

    private List<TbCfgPanelSetting> transToTable(String panelId, Object settings, List<TbCfgPanelSetting> list) {
        if (settings instanceof Map) {
            Map<String, Object> settingsMap = (Map<String, Object>) settings;
            for (String key : settingsMap.keySet()) {
                Object value = settingsMap.get(key);
                if (value == null) continue;
                toPanelSetting(panelId, key, value, list);
            }
        } else if (settings instanceof List) {
            List<Object> settingsList = (List<Object>) settings;
            int size = settingsList.size();
            int digit = String.valueOf(size).length();
            for (int i = 0; i < size; i++) {
                Object value = settingsList.get(i);
                if (value == null) continue;
                toPanelSetting(panelId, String.format("%0" + digit + "d", i), value, list);
            }
        }
        return list;
    }

    private void toPanelSetting(String id, String key, Object value, List<TbCfgPanelSetting> list) {
        TbCfgPanelSetting setting = new TbCfgPanelSetting();
        setting.setREF(id);
        setting.setKEY(key);
        list.add(setting);
        if (value instanceof String) {
            setting.setVALUE((String) value);
            setting.setVALUE_TYPE(ValueType.STRING);
        } else if (value instanceof Number) {
            setting.setVALUE(String.valueOf(value));
            setting.setVALUE_TYPE(ValueType.NUMBER);
        } else if (value instanceof Boolean) {
            setting.setVALUE(String.valueOf(value));
            setting.setVALUE_TYPE(ValueType.BOOLEAN);
        } else if (value instanceof Map) {
            String refId = id + SUB_SEPARATOR + key;
            setting.setVALUE(refId);
            setting.setVALUE_TYPE(ValueType.MAP);
            transToTable(refId, value, list);
        } else if (value instanceof List) {
            String refId = id + SUB_SEPARATOR + key;
            setting.setVALUE(refId);
            setting.setVALUE_TYPE(ValueType.ARRAY);
            transToTable(refId, value, list);
        }
    }

    private <T> T reverseTransform(String panelId, T target) {
        Map<String, Object> contextMap = new HashMap<String, Object>();
        contextMap.put(panelId, target);
        List<TbCfgPanelSetting> settings = dao.queryPanelSetting(panelId);
        for (TbCfgPanelSetting setting : settings) {
            String id = setting.getREF();
            Object ref = contextMap.get(id);
            if (ref == null) continue;
            String key = setting.getKEY();
            String value = setting.getVALUE();
            ValueType valueType = setting.getVALUE_TYPE();
            Object valueRef;
            switch (valueType) {
                case MAP:
                    valueRef = new HashMap();
                    contextMap.put(value, valueRef);
                    break;
                case ARRAY:
                    valueRef = new ArrayList();
                    contextMap.put(value, valueRef);
                    break;
                case NUMBER:
                    valueRef = Double.parseDouble(value);
                    break;
                case BOOLEAN:
                    valueRef = Boolean.parseBoolean(value);
                    break;
                default:
                    valueRef = value;
            }
            setValue(ref, key, valueRef);
        }
        return target;
    }

    private Object setValue(Object ref, String key, Object value) {
        if (ref instanceof Map) {
            ((Map) ref).put(key, value);
        } else if (ref instanceof List) {
            ((List) ref).add(value);
        }
        return ref;
    }
}
